package com.manager.common.quartz;

import com.manager.common.quartz.impl.CornJonEntity;
import com.manager.common.quartz.impl.IntervalJonEntity;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class QuartzManager {

    private Logger logger = LoggerFactory.getLogger(QuartzManager.class);

    private static QuartzManager instance = new QuartzManager();

    private Map<String, JobEntity> jobEntityMap = new HashMap<String, JobEntity>();

    private final static SchedulerFactory schedulerFactory = new StdSchedulerFactory();

    private final static String JOB_GROUP_NAME = "jobGroupName";

    private final static String TRIGGER_GROUP_NAME = "triggerGroupName";

    public final static String JOB_PARAMS_KEY_NAME = "jobParamsKeyName";

    private QuartzManager() {
    }

    public static QuartzManager getInstance() {
        return instance;
    }

    public void addJob(JobEntity jobEntity) throws Exception {
        synchronized (jobEntityMap) {
            if (jobEntity instanceof IntervalJonEntity) {
                addIntervalJob((IntervalJonEntity) jobEntity);
            } else if (jobEntity instanceof CornJonEntity) {
                addCornJob((CornJonEntity) jobEntity);
            }
            jobEntityMap.put(jobEntity.getJobName(), jobEntity);
            logger.info("addJob JobEntity:" + jobEntity.getJobName());
        }
    }

    public void deleteJob(String jobName) throws Exception {
        synchronized (jobEntityMap) {
            if(!jobEntityMap.containsKey(jobName)){
                return;
            }
            TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
            JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);

            Scheduler scheduler = schedulerFactory.getScheduler();

            scheduler.pauseTrigger(triggerKey);
            scheduler.unscheduleJob(triggerKey);
            scheduler.deleteJob(jobKey);
            jobEntityMap.remove(jobName);
            logger.info("deleteJob JobEntity:" + jobName);
        }
    }

    public  void resumeJob(String jobName) throws SchedulerException {
        synchronized (jobEntityMap) {
            JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
            Scheduler scheduler = schedulerFactory.getScheduler();
            scheduler.resumeJob(jobKey);
            logger.info("resumeJob JobEntity:" + jobName);
        }
    }

    public  void pauseJob(String jobName) throws SchedulerException {
        synchronized (jobEntityMap) {
            JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
            Scheduler scheduler = schedulerFactory.getScheduler();
            scheduler.pauseJob(jobKey);
            logger.info("pauseJob JobEntity:" + jobName);
        }
    }

    public  boolean updateCornJobDate(String jobName,String corn) throws Exception {

        CornJonEntity jobEntity = (CornJonEntity) jobEntityMap.get(jobName);
        if(jobEntity == null){
            return false;
        }
        jobEntity.setCorn(corn);
        updateJob(jobEntity);
        return true;
    }
    public  boolean updateIntervalJobDate(String jobName,Integer interval,IntervalScheduleTimeEnum scheduleTimeEnum) throws Exception {

        IntervalJonEntity jobEntity = (IntervalJonEntity) jobEntityMap.get(jobName);
        if(jobEntity == null){
            return false;
        }
        jobEntity.setInterval(interval);
        jobEntity.setIntervalScheduleTimeEnum(scheduleTimeEnum);
        updateJob(jobEntity);
        return true;
    }


    public boolean updateJob(JobEntity jobEntity) throws Exception{
        TriggerKey triggerKey = new TriggerKey(jobEntity.getJobName(), TRIGGER_GROUP_NAME);
        Scheduler scheduler = schedulerFactory.getScheduler();
        Trigger trigger = scheduler.getTrigger(triggerKey);

        if (trigger == null) {
            return false;
        }

        deleteJob(jobEntity.getJobName());
        addJob(jobEntity);

        logger.info("updateJobDate JobEntity:" + jobEntity.getJobName());

        return true;
    }

    public <T> T getJob(String jobName) throws Exception {
        synchronized (jobEntityMap) {
            return (T)jobEntityMap.get(jobName);
        }
    }

    public boolean isJobRunning(String jonName) throws SchedulerException {
        synchronized (jobEntityMap){
            Scheduler scheduler = schedulerFactory.getScheduler();
            List<JobExecutionContext> list = scheduler.getCurrentlyExecutingJobs();
            for (JobExecutionContext jobExecutionContext : list) {
                if (jonName.equals(jobExecutionContext.getTrigger().getJobKey().getName())) {
                    return true;
                }
            }
            return false;
        }
    }

    public  boolean isJobExist(String jonName) throws SchedulerException {
        synchronized (jobEntityMap){
            return jobEntityMap.containsKey(jonName);
        }
    }

    private void addIntervalJob(IntervalJonEntity jobEntity) throws Exception {
        int interval = getSeconds(jobEntity.getInterval(),jobEntity.getIntervalScheduleTimeEnum());
        Scheduler scheduler = schedulerFactory.getScheduler();
        JobDetail jobDetail = JobBuilder.newJob(jobEntity.getJobClass()).withIdentity(jobEntity.getJobName(), JOB_GROUP_NAME).build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(jobEntity.getJobName(), TRIGGER_GROUP_NAME).withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(Integer.valueOf(interval)).withRepeatCount(jobEntity.getRepeatNum()))
                .build();
        jobDetail.getJobDataMap().put(JOB_PARAMS_KEY_NAME, jobEntity.getJobParams());
        scheduler.scheduleJob(jobDetail, trigger);

        if (!scheduler.isShutdown()) {
            scheduler.start();
        }

    }

    private void addCornJob(CornJonEntity jobEntity) throws Exception {
        Scheduler scheduler = schedulerFactory.getScheduler();
        JobDetail jobDetail = JobBuilder.newJob(jobEntity.getJobClass()).withIdentity(jobEntity.getJobName(), JOB_GROUP_NAME).build();
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobEntity.getJobName(), TRIGGER_GROUP_NAME)
                .withSchedule(CronScheduleBuilder.cronSchedule(jobEntity.getCorn())).build();

        jobDetail.getJobDataMap().put(JOB_PARAMS_KEY_NAME, jobEntity.getJobParams());
        scheduler.scheduleJob(jobDetail, trigger);

        if (!scheduler.isShutdown()) {
            scheduler.start();
        }
    }

    private Integer getSeconds(Integer interval,IntervalScheduleTimeEnum intervalScheduleTimeEnum) {
        if(IntervalScheduleTimeEnum.DAY == intervalScheduleTimeEnum){
            interval = interval * 24 * 60 * 60;
        }else if(IntervalScheduleTimeEnum.HOUR == intervalScheduleTimeEnum){
            interval = interval * 60 * 60 ;
        }else if(IntervalScheduleTimeEnum.MINUTE == intervalScheduleTimeEnum){
            interval = interval * 60;
        }else if(IntervalScheduleTimeEnum.SECOND == intervalScheduleTimeEnum){
            interval = interval;
        }
        return interval;
    }

    public String getJobParamsKeyName() {
        return JOB_PARAMS_KEY_NAME;
    }
}
